package com.stox.shared.indicator.model;

import com.stox.shared.indicator.model.config.BaseIndicatorConfig;
import com.stox.shared.indicator.model.enumeration.IndicatorDisplayType;
import com.stox.shared.indicator.model.enumeration.IndicatorPosition;

public class ExponencialMovingAverage extends AbstractIndicator<Double, BaseIndicatorConfig>{

	public static final ExponencialMovingAverage INSTANCE = new ExponencialMovingAverage();
	
	private ExponencialMovingAverage() {
		super("EMA");
	}

	@Override
	public IndicatorDisplayType getDisplayType(final BaseIndicatorConfig config) {
		return IndicatorPosition.INDEPENDENT.equals(getPosition(config)) ? IndicatorDisplayType.AREA : IndicatorDisplayType.LINE;
	}

	@Override
	public IndicatorPosition getPosition(final BaseIndicatorConfig config) {
		switch (config.getBarValue()) {
			case VOLUME:
				return IndicatorPosition.OVERLAY_VOLUME;
			case RANGE:
				return IndicatorPosition.INDEPENDENT;
			default:
				return IndicatorPosition.OVERLAY_PRICE;
		}
	}

	@Override
	public Double getValue(final BaseIndicatorConfig configuration, final Double[] in, final int index) throws UnsupportedOperationException {
		final int span = configuration.getSpan();
		if(in.length <= index + span){
			return null;
		}
		double previousEMA = in[index+span];
		double multiplier = 2/(span + 1);
		for (int i = index; i < (index + span); i++) {
			previousEMA = (in[index] - previousEMA)*multiplier + previousEMA;
		}
		return previousEMA;
	}

	@Override
	public Double[] getValues(final BaseIndicatorConfig configuration, final Double[] values) throws UnsupportedOperationException {
		final Double[] result = new Double[values.length];
		
		final double span = configuration.getSpan();
		double multiplier = 2/(span + 1);
		final int size = values.length;
		double previousEMA = values[size - 1];
		for (int i = size - 1; i >= 0; i--) {
			if (null == values[i]) {
				continue;
			}
			previousEMA = (values[i] - previousEMA)*multiplier + previousEMA;
			if (i > (size - 1 - span)) {
				continue;
			}
			result[i] = previousEMA;
		}
		return result;
	}
	
	@Override
	public BaseIndicatorConfig createDefaultConfiguration() {
		return new BaseIndicatorConfig();
	}
}
